/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.model.disc.analysismodel;

import java.text.DecimalFormat;
import java.util.ListIterator;

import br.ufmg.dees.insane.materialMedia.material.Material;
import br.ufmg.dees.insane.model.disc.element.ParametricElement;
import br.ufmg.dees.insane.model.disc.fem.FemModel;
import br.ufmg.dees.insane.model.disc.node.Node;
import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.IVector;

/**
*A class representing an bar analysis model of a ParametricElement.
*
*@author Lucas, Marcelo & Pitangueira, Roque
*@version 1.0
*@since September 2004
*@see model.discrete.element.ParametricElement
*/

public abstract class LineAnalysisM extends AnalysisModel implements java.io.Serializable 
{
	/** Return the normal vector according this analysis model.
	*@param a The IMatrix of local derivates.
	*@param b The IMatrix of nodal coordinates.
	*@return The normal vector according this analysis model.
	*/
	protected abstract IVector getNormalVector(IMatrix a, IMatrix b);
	
//********************************************************************************

	/** Constructs a LineAnalysisM analysis model, and sets dominion to 1.*/	
	public LineAnalysisM()
	{
		this.setDominion(1);
	}
	
//********************************************************************************

	/** Returns the B matrix related to this PlaneAnalysisM 
	*@param dl The matrix containing local derivates of shape functions.
	*@param n The vector containing shape functions in natural coordinates.
	*@param cN The matrix containing nodal coordinates in cartesian system.
	*@return The matrix B 
	*/
	public IMatrix mountBMatrix(IMatrix dl, IVector n, IMatrix cN) 
	{
//dG tem uma linha e nNos colunas, portanto o mesmo tamanho de dl.
		IMatrix invertJacobian;
		IMatrix dG = new IMatrix(1,dl.getNumCol());
		IMatrix b = new IMatrix(1,(this.getNdf()*dG.getNumCol()));
		IMatrix normal = new IMatrix(1,this.getNdf());
		IVector aux = new IVector(dG.getNumCol());
		
		dG.setZero();
		b.setZero();
		normal.setZero();
		aux.zero();
		
		invertJacobian = this.invertJacobian(this.getJacobian(dl, cN));
		dG.mul(invertJacobian, dl);
//atribui a aux os elementos da primeira e unica linha de dG
		dG.getRow(0,aux);
//atribui ao vetor normal o retorno do metodo getNormalVector
		normal.setRow(0,this.getNormalVector(dl, cN));
		b.mul(normal, this.mountMatrixN(aux));
		
			return(b);
	}
	
//********************************************************************************	
	
	/** Prints in the screen a table with the valid nodal displacements for this AnalysisModel type.
	*@param mod The FemModel which contains the data to be printed.
	*/
	public void printDisplacements(FemModel mod)
	{
		DecimalFormat fmt = new DecimalFormat();
		fmt.applyPattern("0.000E00");
		Node node;
		ListIterator nodes = mod.getNodesList().listIterator();
		System.out.println("NODE DISPLACEMENTS:");
		System.out.println("Node" +"\t\t"+ "Dx" +"\t\t"+ "Dy" +"\t\t\t"+ "Dz");

		while (nodes.hasNext()) 
		{
			node = (Node) nodes.next();
			System.out.println("Node " + node.getLabel() +"\t"+ fmt.format(node.getDisplacement(0)) +"\t\t"+ fmt.format(node.getDisplacement(1)) +"\t\t"+ fmt.format(node.getDisplacement(2)));
		}
		System.out.println("\t");

	}
	
//********************************************************************************
	/** Prints in the screen a table with the valid support reactions for this AnalysisModel type.
	*@param mod The FemModel which contains the data to be printed.
	*/
	public void printReactions(FemModel mod)
	{
		Node node;
		ListIterator nodes = mod.getNodesList().listIterator();
		System.out.println("SUPPORT REACTIONS:");
		System.out.println("Node" +"\t"+ "Rx");
		
		while (nodes.hasNext())
		{
			node = (Node) nodes.next();
			boolean hasRestraint = false;
			for (int i=0; i<(mod.getGlobalAnalysisModel().getNdf()); i++)
				if (node.getRestraint(i))
					hasRestraint = true;
			if (hasRestraint)
				System.out.println("Node " + node.getLabel() +"\t"+ (node.getReaction(0)));
		}
		System.out.println("\t");
	}
	
//********************************************************************************

	/** Prints in the screen a table with the valid actions at elements' extremities for the AnalysisModel type.
	*@param femModel The FemModel which contains the data to be printed.
	*/
	public void printActionsAtExtremities(FemModel femModel)
	{
	}
	
//********************************************************************************
	
	/** Return the integration factor according to analysis model type.
	*This method will be important for AxiSymetricAnalysisM.
	*@param n The vector containing the shape functions.
	*@param cN The matrix containing the nodal coordinates in cartesian system.
	*@return The integration factor wich for this analysis model is equals to one.
	*/
	public double getStiffnessFactor(IVector n, IMatrix cN)
	{
		return 1;
	}
	
//********************************************************************************

	/** Mounts the shape function matrix accordingly to the AnalysisModel type with the values of two IVectors.<br>
	*The first IVector must contain the shape functions values which will be put in the upper part of the matrix.<br>
	*The second IVector must contain the shape functions values which will be put in the lower part of the matrix (related to the derivated shape functions).
	*@param n1 A IVector containing the shape functions values which will be put in the upper part of the matrix.
	*@param n2 A IVector containing the shape functions values which will be put in the upper part of the matrix.
	*@return The shape function matrix accordingly to the AnalysisModel type.
	*/
	public IMatrix mountMatrixN(IVector n1, IVector n2)
	{
		return null;
	}
	
	/**Return the matrix with the shape functions ordered according the AnalysisModel.
	*@param n1 The IVector containing the values of shape functions evalueted in one point.
	*@return matrixN The IMatrix with the shape functions ordered according the AnalysisModel.
	*/
	public IMatrix mountMatrixN(IVector n1)
	{
		IMatrix matrixN = new IMatrix(this.getNdf(),(this.getNdf()*n1.getSize()));
		matrixN.setZero();
		
		for(int i = 0; i < (n1.getSize()); i++)
		{
			for(int j = 0; j < (this.getNdf()); j++)
			{
				matrixN.setElement(j, (((this.getNdf())*i)+j), (n1.getElement(i)));
			}
		}
			return matrixN;
	}
	
//********************************************************************************
	
	/** Return the jacobian matrix.
	*@param dl The matrix of local derivates.
	*@param cN The matrix of nodal coordinates.
	*@return jacobian The jacobian matrix.
	*/
	public IMatrix getJacobian(IMatrix dl, IMatrix cN)
	{
		IVector n_Xi = new IVector(dl.getNumCol());
		IMatrix aux = new IMatrix(this.getNdf(),1);
//foi necessario definir jacobian(1,1) porque o retorno deste metodo pede uma IMatrix
		IMatrix jacobian = new IMatrix(1,1);
		double j1 = 0;
		double j2 = 0;
		double j3 = 0;
		
		n_Xi.zero();
		aux.setZero();
		jacobian.setZero();
		
		IVector normalVector = this.getNormalVector(dl,cN);
		dl.getRow(0,n_Xi);
		aux.mul((this.mountMatrixN(n_Xi)),cN);
		
//		double j = (normalVector.getElement(0)*aux.getElement(0,0)) + (normalVector.getElement(1)*aux.getElement(1,0)) + (normalVector.getElement(2)*aux.getElement(2,0));
		j1 = (normalVector.getElement(0)*aux.getElement(0,0));
		if(this.getValidEquation(1))
			j2 = (normalVector.getElement(1)*aux.getElement(1,0));
		if(this.getValidEquation(2))
			j3 = (normalVector.getElement(2)*aux.getElement(2,0));
		
		jacobian.setElement(0,0,(j1+j2+j3));
		
		return(jacobian);
	}
	
//********************************************************************************
	
	/** Return the normal vector according this analysis model.
	*@param a The IMatrix of local derivates.
	*@param b The IMatrix of nodal coordinates.
	*@return The normal vector according this analysis model.
	*/
/*	private IVector getNormalVector(IMatrix a, IMatrix b)
	{
//		int nNos = (b.getNumRow()/this.getNdf());
		int nNos = (a.getNumCol());
		IVector normal = new IVector(this.getNdf());
		IVector vectorX = new IVector(nNos);
		IVector vectorY = new IVector(nNos);
		IVector vectorZ = new IVector(nNos);
		IVector n_Xi = new IVector(nNos);
		
		normal.zero();
		vectorX.zero();
		vectorY.zero();
		vectorZ.zero();
		n_Xi.zero();
		
		for(int i = 0; i < nNos; i++)
		{
			if(myAnalysisModel.getValidEquation(0))
				vectorX.setElement(i,b.getElement(this.getNdf()*i,0));
			if(myAnalysisModel.getValidEquation(1))
				vectorY.setElement(i,b.getElement(this.getNdf()*i+1,0));
			if(myAnalysisModel.getValidEquation(2))
				vectorZ.setElement(i,b.getElement(this.getNdf()*i+2,0));
		}
		
		a.getRow(0,n_Xi);
		
		double dX_dXi = n_Xi.dot(vectorX);
		double dY_dXi = n_Xi.dot(vectorY);
		double dZ_dXi = n_Xi.dot(vectorZ);
		double dXi_dS = 1/(Math.sqrt((dX_dXi*dX_dXi)+(dY_dXi*dY_dXi)+(dZ_dXi*dZ_dXi)));
		
		normal.setElement(0,(dX_dXi*dXi_dS));
		normal.setElement(1,(dY_dXi*dXi_dS));
		normal.setElement(2,(dZ_dXi*dXi_dS));
		
		return normal;
	}
*/
//********************************************************************************
	
	/** Mounts the matrix of the material properties for this line analysis model type.
	*@param a The matrix of material properties.
	*@return matrix D related to analysis model type 
	*/
	public IMatrix mountDMatrix(double[][] a)
	{
		IMatrix d = new IMatrix(1,1);
		d.setZero();
		d.setElement(0,0,(a[0][0]));
		
			return d;
	}
	
//********************************************************************************
	
	/** Return the number of active stresses according to this Analysis model type.*/	
	public int getNumberOfActiveStress()
	{
		return 1;
	}
	
//********************************************************************************
	
	/** Return the number of active strains according to this Analysis model type.*/
	public int getNumberOfActiveStrains()
	{
		return 1;
	}
	
//********************************************************************************
	
	/** Return the non zero stresses that perform in one point. 
	*@param a The IVector containing stresses of the point.
	*@param b The Material that will be used to obtain material properties.
	*@return stressVector The IVector according this Line Analysis Model.
	*/
	public IVector getStressVector(IVector a, Material b)
	{
		return a;
	}
	
//********************************************************************************
	
	/** Return the non zero strains that perform in one point. 
	*@param a The IVector containing strains of the point.
	*@param b The Material that will be used to obtain material properties.
	*@return strainVector The IVector according this Line Analysis Model.
	*/
	public IVector getStrainVector(IVector a, Material b)
	{
		return a;
	}
	
//********************************************************************************
	
	/** Return the String representing the non zero stresses of this Analysis Model.
	*@return The string containing the label of non zero stresses of this Analysis Model.
	*/
	public String getStressLabels()
	{
		return ("sigmaXX");
	}
	
//********************************************************************************
	
	/** Return the string representing the non zero strains of this Plane Analysis Model.
	*@return The string containing the label of non zero strains of this Plane Analysis Model.
	*/
	public String getStrainLabels()
	{
		return ("epsilonXX");
	}
	
//********************************************************************************
	
	/** Returns the type of the Shape adequate to the type of AnalysisModel.
	*@return The type of the Shape adequate to the type of AnalysisModel.
	*/
	public String getDefaultShapeType()
	{
		return null;
	}
	
	/** Returns the nodal rotation matrix of the specified ParametricElement, accordingly to this AnalysisModel type.
	*@param elm The ParametricElement whose nodal rotation matrix is desired.
	*@return The nodal rotation matrix of the specified ParametricElement, accordingly to this AnalysisModel type.
	*/
	public IMatrix nodalRotationMatrix(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the local stiffness matrix of the specified ParametricElement, accordingly to its AnalysisModel type.<br>
	*This matrix does not consider the possible liberations at the extremities of the ParametricElement.
	*@param elm The ParametricElement whose local stiffness matrix is desired.
	*@return The local stiffness matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*/
	public IMatrix localStiffnessMatrix(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the corrected local stiffness matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*This matrix is corrected to consider the liberations at the extremities of the ParametricElement.
	*@param elm The ParametricElement whose corrected local stiffness matrix is desired.
	*@return The corrected local stiffness matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*/
	public IMatrix localCorrectedStiffnessMatrix(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the transformation matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*@param elm The ParametricElement whose transformation matrix is desired.
	*@return The transformation matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*/
	public IMatrix transformationMatrix(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the local equivalent nodal force vector of the specified ParametricElement, accordingly to the AnalysisModel type.
	*This vector does not consider the possible liberations at the extremities of the ParametricElement.
	*@param elm The ParametricElement whose local equivalent nodal force vector is desired.
	*@return The local equivalent nodal force vector of the specified ParametricElement, accordingly to the AnalysisModel type.
	*/
	public IVector localEquivalentForceVector(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the corrected local equivalent nodal force vector of the specified ParametricElement, accordingly to the AnalysisModel type.
	*This matrix is corrected to consider the liberations at the extremities of the ParametricElement.
	*@param elm The ParametricElement whose corrected local equivalent nodal force vector is desired.
	*@return The corrected local equivalent nodal force vector of the specified ParametricElement, accordingly to the AnalysisModel type.
	*/
	public IVector localCorrectedEquivalentForceVector(ParametricElement elm)
	{
		return null;
	}
	
//********************************************************************************

	/** Return the inverse of jacobian matrix.
	*@param a The jacobian matrix.
	*@return the inverse of jacobian matrix.
	*/
	protected IMatrix invertJacobian(IMatrix a)
	{
		double inv = 1/(a.getElement(0,0));
		IMatrix b = new IMatrix(1,1);
		b.setZero();
		b.setElement(0,0,inv);
		
		return (b);
	}

//********************************************************************************
	
	public static void imprimeMatriz(IMatrix a)
	{
		for (int i = 0; i < a.getNumRow(); i++)
		{
			System.out.println();
			for (int j = 0; j < a.getNumCol(); j++)
			{
				System.out.print(a.getElement(i, j));
				System.out.print("\t");
			}
		}
		System.out.println("TAMANHO DA MATRIZ: "+a.getNumRow()+" x "+a.getNumCol());
	}
	
	public static void imprimeVetor(IVector a)
	{
		for (int i=0; i<a.getSize(); i++)
		{
			System.out.println();
			System.out.print(a.getElement(i));
			System.out.print("\t");
		}
		System.out.println("TAMANHO DO VETOR: "+a.getSize());
	}
	
//*****************************************************************************	
}
